﻿using System;
using System.Windows.Data;
using System.Windows.Controls;
using System.Windows.Media.Animation;
using System.Windows.Interactivity;
using System.Windows;
using System.ComponentModel;

namespace TextOutInBehavior.Wpf
{
    public class TextOutInStoryBehavior : Behavior<TextBlock>
    {

        private string OriginalText = null;
        private string NewText = null;
        
        [Category("Storyboard"), Browsable(true), Description("The Storyboard play with original text")]
        public Storyboard OutStoryboard
        {
            get
            {
                return base.GetValue(OutStoryboardProperty) as Storyboard;
            }
            set
            {
                base.SetValue(OutStoryboardProperty, value);
            }
        }

        [Category("Storyboard"), Browsable(true), Description("The Storyboard play with new text")]
        public Storyboard InStoryboard
        {
            get
            {
                return base.GetValue(InStoryboardProperty) as Storyboard;
            }
            set
            {
                base.SetValue(InStoryboardProperty, value);
            }
        }

        
        public readonly DependencyProperty OutStoryboardProperty = DependencyProperty.Register("OutStoryboard", typeof(Storyboard), typeof(TextOutInStoryBehavior));
        public readonly DependencyProperty InStoryboardProperty = DependencyProperty.Register("InStoryboard", typeof(Storyboard), typeof(TextOutInStoryBehavior));
       

        protected override void OnAttached()
        {
            base.OnAttached();
            
            OriginalText = (string)AssociatedObject.GetValue(TextBlock.TextProperty);
            Binding.AddTargetUpdatedHandler(AssociatedObject, new EventHandler<DataTransferEventArgs>(UpdatedEvent));
            OutStoryboard.Completed += OutStoryboard_Completed;
        }

        private void OutStoryboard_Completed(object sender, EventArgs e)
        {
            AssociatedObject.SetCurrentValue(TextBlock.TextProperty, NewText);
            OriginalText = NewText;
            AssociatedObject.BeginStoryboard(InStoryboard);
        }

        private void UpdatedEvent(object sender, DataTransferEventArgs e)
        {
            string CurrntText = (string) AssociatedObject.GetValue(TextBlock.TextProperty);
            if (CurrntText != OriginalText)
            {
                AssociatedObject.SetCurrentValue(TextBlock.TextProperty, OriginalText);
                NewText = CurrntText;
                AssociatedObject.BeginStoryboard(OutStoryboard);
            }
        }
    }



    public class TextOutInFadeBehavior : Behavior<TextBlock>
    {

        private string OriginalText = null;
        private string NewText = null;
        private bool isAnimatingIn;
        private bool isAnimatingOut;

        [Category("Duration"), Browsable(true), Description("The fade duration of original text")]
        public System.Windows.Duration FadeOutDuration { get; set; }
        [Category("Duration"), Browsable(true), Description("The fade duration of new text")]
        public System.Windows.Duration FadeInDuration { get; set; }


        private DoubleAnimation AnimationOut;
        private DoubleAnimation AnimationIn;

        protected override void OnAttached()
        {
            base.OnAttached();

            AnimationOut = new DoubleAnimation(1, 0, FadeOutDuration, FillBehavior.HoldEnd);
            AnimationIn = new DoubleAnimation(0, 1, FadeInDuration, FillBehavior.HoldEnd);
            OriginalText = (string)AssociatedObject.GetValue(TextBlock.TextProperty);
            DependencyPropertyDescriptor dp = DependencyPropertyDescriptor.FromProperty(TextBlock.TextProperty, typeof(TextBlock));
            dp.AddValueChanged(AssociatedObject, new EventHandler(TextChanged));

            isAnimatingIn = false;
            isAnimatingOut = false;
            AnimationOut.Completed += AnimationOut_Completed;
            AnimationIn.Completed += AnimationIn_Completed;
        }

        private void TextChanged(object sender, EventArgs e)
        {            
            string currentText = (string)AssociatedObject.GetValue(TextBlock.TextProperty);

            if (isAnimatingOut && isAnimatingIn)
            {
                NewText = currentText;
                OriginalText = currentText;
                AssociatedObject.SetCurrentValue(TextBlock.TextProperty, currentText);
                return;
            }

            if (isAnimatingOut)
            {
                AssociatedObject.SetCurrentValue(TextBlock.TextProperty, OriginalText);
                NewText = currentText;
                return;
            }
            if (isAnimatingIn)
            {
                return;
            }

            if (currentText != OriginalText)
            {
                AssociatedObject.SetCurrentValue(TextBlock.TextProperty, OriginalText);
                NewText = currentText;
                isAnimatingOut = true;
                AssociatedObject.BeginAnimation(TextBlock.OpacityProperty, AnimationOut);
            }
        }

        private void UpdatedEvent(object sender, DataTransferEventArgs e)
        {
            string CurrntText = (string)AssociatedObject.GetValue(TextBlock.TextProperty);
            if (CurrntText != OriginalText)
            {
                AssociatedObject.SetCurrentValue(TextBlock.TextProperty, OriginalText);
                NewText = CurrntText;
                AssociatedObject.BeginAnimation(TextBlock.OpacityProperty, AnimationOut);
            }
        }


        private void AnimationOut_Completed(object sender, EventArgs e)
        {
            isAnimatingIn = true;
            OriginalText = NewText;
            AssociatedObject.SetCurrentValue(TextBlock.TextProperty, NewText);
            isAnimatingOut = false;
            AssociatedObject.BeginAnimation(TextBlock.OpacityProperty, AnimationIn);
        }

        private void AnimationIn_Completed(object sender, EventArgs e)
        {
            OriginalText = (string)AssociatedObject.GetValue(TextBlock.TextProperty);
            isAnimatingIn = false;
        }
    }
}
